package org.infosys.basic.service.impl;

import com.alibaba.fastjson.JSONObject;
import org.infosys.basic.constant.BaseConstants;
import org.infosys.basic.exception.BusinessException;
import org.infosys.basic.service.ILoginService;
import org.infosys.basic.utils.*;
import org.infosys.basic.vo.LoginVo;
import org.infosys.user.domain.Logininfo;
import org.infosys.user.domain.User;
import org.infosys.user.domain.Wxuser;
import org.infosys.user.dto.WxDto;
import org.infosys.user.mapper.LogininfoMapper;
import org.infosys.user.mapper.UserMapper;
import org.infosys.user.mapper.WxuserMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl extends BaseServiceImpl<Logininfo> implements ILoginService {

    @Autowired
    private LogininfoMapper logininfoMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private WxuserMapper wxuserMapper;

    @Autowired
    private UserMapper userMapper;

    /**
    * @Title: accountLogin
    * @Description: 账号登录
    * @Author: hank
    * @Version: 1.0
    * @Date:  2022/7/7 16:41
    * @Parameters: [loginVo]
    * @Return java.util.HashMap<java.lang.String,java.lang.Object>
    */
    @Override
    public HashMap<String, Object> accountLogin(LoginVo loginVo) {
        // 判断参数非空
        String username = loginVo.getUsername();
        String password = loginVo.getPassword();
        Integer type = loginVo.getType();
        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password) || StringUtils.isEmpty(type)) {
            throw new BusinessException("参数不能为空！");
        }
        // 根据用户名和type查询
        Logininfo logininfo = logininfoMapper.loadByUsernameAndType(loginVo);
        if (ObjectUtils.isEmpty(logininfo)) {
            throw new BusinessException("用户名或密码错误,请重新输入");
        }
        // 存在，则判断密码是否正确
        String saltPas = MD5Utils.encrypByMd5(logininfo.getSalt() + password);
        if (!logininfo.getPassword().equals(saltPas)) {
            throw new BusinessException("用户名或密码错误,请重新输入");
        }
        // 此时账号密码都没有问题
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(token, logininfo, 30, TimeUnit.MINUTES);
        // 用户敏感信息置空
        logininfo.setPassword("");
        logininfo.setSalt("");
        HashMap<String, Object> map = new HashMap<>();
        map.put("token", token);
        map.put("logininfo", logininfo);
        return map;
    }

    /**
    * @Title: wechatLogin
    * @Description: 微信登录
    * @Author: hank
    * @Version: 1.0
    * @Date:  2022/7/10 17:45
    * @Parameters: [wxDto]
    * @Return org.infosys.basic.utils.AjaxResult
    */
    @Override
    @Transactional
    public AjaxResult wechatLogin(WxDto wxDto) {
        String code = wxDto.getCode();

        if(StringUtils.isEmpty(code)) {
            throw new BusinessException("参数不能为空!");
        }
        // 拼接微信公共接口路径
        String tokenUrl = BaseConstants.WechatConstant.TOKEN_URL
                    .replace("APPID", BaseConstants.WechatConstant.APPID)
                    .replace("SECRET", BaseConstants.WechatConstant.SECRET)
                    .replace("CODE", code);

        // 发起请求，获取到json格式的字符串
        String jsonStr = HttpUtil.httpGet(tokenUrl);
        // 把字符串解析为json
        JSONObject jsonObject = JSONObject.parseObject(jsonStr);
        // 根据openid查询wxuser表
        Wxuser wxuser = wxuserMapper.loadByOpenId(jsonObject.getString("openid"));
        if (!ObjectUtils.isEmpty(wxuser) && wxuser.getUserId() != null) {
            // 根据userid查询出logininfo
            Logininfo logininfo = logininfoMapper.loadByUserId(wxuser.getUserId());
            UUID token = UUID.randomUUID();
            // 存redis
            redisTemplate.opsForValue().set(token, logininfo, 30, TimeUnit.MINUTES);
            // 去除敏感信息
            logininfo.setSalt("");
            logininfo.setPassword("");
            // 放入map中
            HashMap<String, Object> map = new HashMap<>();
            map.put("token", token);
            map.put("logininfo", logininfo);
            return AjaxResult.me().setResultObj(map);
        }
        // 不存在需要让前端跳转到账号绑定的页面
        StringBuffer sbr = new StringBuffer()
                .append("?accessToken=").append(jsonObject.getString("access_token"))
                .append("&openId=").append(jsonObject.getString("openid"));
        return AjaxResult.me().setSuccess(false).setResultObj(sbr).setMsg("nobinder");
    }

    /**
    * @Title: binder
    * @Description: 微信登录绑定账号
    * @Author: hank
    * @Version: 1.0
    * @Date:  2022/7/10 20:14
    * @Parameters: [wxDto]
    * @Return java.util.HashMap<java.lang.String,java.lang.Object>
    */
    @Override
    @Transactional
    public HashMap<String, Object> binder(WxDto wxDto) {
        String phone = wxDto.getPhone();
        String verifyCode = wxDto.getVerifyCode();
        String accessToken = wxDto.getAccessToken();
        String openId = wxDto.getOpenId();
        // 非空判断
        if (StringUtils.isEmpty(phone) || StringUtils.isEmpty(verifyCode) || StringUtils.isEmpty(accessToken) || StringUtils.isEmpty(openId)) {
            throw new BusinessException("参数不能为空！");
        }
        // 判断短信验证码是否正确
        isVerifyCode(wxDto);
        // 根据电话查询t_user表
        User user = userMapper.loadByPhone(phone);
        Logininfo logininfo = null;
        if(ObjectUtils.isEmpty(user)) {
            // 查询不到，需要入库三张表
            user = initUser(wxDto);
            // 把user拷贝到logininfo中
            logininfo = user2Logininfo(user);
            logininfoMapper.save(logininfo);
            user.setLogininfoId(logininfo.getId());
            userMapper.save(user);
        } else {
            logininfo = logininfoMapper.loadByUserId(user.getId());
        }
        // 根据accessToken+openId获取个人信息
        String wxUserUrl = BaseConstants.WechatConstant.WXUSER_URL
                .replace("ACCESS_TOKEN", accessToken)
                .replace("OPENID", openId);
        String wxUserJsonStr = HttpUtil.httpGet(wxUserUrl);
        Wxuser wxuser = JSONObject.parseObject(wxUserJsonStr, Wxuser.class);
        wxuser.setUserId(user.getId());
        // 入库
        wxuserMapper.save(wxuser);
        // 生成token保存到redis中，返回前端
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(token, logininfo, 30, TimeUnit.MINUTES);
        // 敏感信息置空
        logininfo.setSalt("");
        logininfo.setPassword("");
        HashMap<String, Object> map = new HashMap<>();
        map.put("token", token);
        map.put("logininfo", logininfo);
        return map;
    }

    /**
    * @Title: isVerifyCode
    * @Description: 校验短信验证码
    * @Author: hank
    * @Version: 1.0
    * @Date:  2022/7/10 20:13
    * @Parameters: [wxDto]
    * @Return void
    */
    public void isVerifyCode(WxDto wxDto) {
        String phoneCodeKey = BaseConstants.VerifyCodeConstant.BUSINESS_BINDER_KEY + wxDto.getPhone();
        // 根据rediskey查询
        Object phoneCodeValue = redisTemplate.opsForValue().get(phoneCodeKey);
        if (ObjectUtils.isEmpty(phoneCodeValue)) {
            throw new BusinessException("验证码已过期!");
        }
        // 判断验证码是否正确
        String[] split = phoneCodeValue.toString().split(":");
        if (!split[1].equalsIgnoreCase(wxDto.getVerifyCode())) {
            throw new BusinessException("验证码错误!");
        }
    }

    /**
    * @Title: initUser
    * @Description: 初始化User
    * @Author: hank
    * @Version: 1.0
    * @Date:  2022/7/10 20:34
    * @Parameters: [wxDto]
    * @Return org.infosys.user.domain.User
    */
    private User initUser(WxDto wxDto) {
        String phone = wxDto.getPhone();
        User user = new User();
        user.setUsername(phone);
        user.setPhone(phone);
        // 初始化密码
        String initPwd = "123456";
        // 发送短信
//      SmsUtils.sendCode(phone,"您的初始密码为" + initPwd+ "请尽快修改");
        String salt = StrUtils.getComplexRandomString(32);
        String password = MD5Utils.encrypByMd5(salt + initPwd);
        user.setSalt(salt);
        user.setPassword(password);
        return user;
    }

    /**
    * @Title: user2Logininfo
    * @Description: 拷贝user到logininfo中
    * @Author: hank
    * @Version: 1.0
    * @Date:  2022/7/11 15:15
    * @Parameters: [user]
    * @Return org.infosys.user.domain.Logininfo
    */
    private Logininfo user2Logininfo(User user) {
        Logininfo logininfo = new Logininfo();
        BeanUtils.copyProperties(user, logininfo);
        logininfo.setType(1);
        return logininfo;
    }
}
